package DAO;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import Pojo.Disciplina;
import Pojo.HistoricoTurma;
import Pojo.Nota;
import Pojo.Professor;
import Pojo.Turma;
import Pojo.Historico;

/** Classe DisciplinaDao
 * Essa classe implementa a interface DisciplinaDao para comunicar com arquivo.
 * @author Thiago Schons 
 *
 */
public class DisciplinaDaoImplArquivo implements DisciplinaDao{

	/** Lista de Disciplinas*/
	private List<Disciplina> listaDisciplinas;
	
	/** Atributo constante com o endereço do arquivo onde será armazenada os dados.*/
	private static final String nomeArquivo = "Arquivos/Disciplinas.txt";
	
	/** Atributo onde é guardado o próximo id para inserção na lista.*/
	private int proximoId;
	
	/**
	 * Construtor da classe com um identificador indicando que não é necessário buscar dados do arquivo
	 * @param identificador
	 */
	public DisciplinaDaoImplArquivo(int identificador){
		this.listaDisciplinas = new ArrayList<Disciplina>();
		this.proximoId=0;
	}
	
	/**
	 * Construtor da classe que busca dados no arquivo
	 */
	public DisciplinaDaoImplArquivo(){
		this.listaDisciplinas = new ArrayList<Disciplina>();
		this.proximoId=0;
		this.buscarArmazenamento();
	}
	
	/**
	 * Getter do próximo id da Disciplina
	 * @return próximo id disponível
	 */
	public int getProximoId(){
		return(this.proximoId);
	}
	
	/**
	 * Lista das Disciplinas. 
	 * @return Lista das Disciplinas.
	 */
	public List<Disciplina> getListaDisciplina(){
		return(this.listaDisciplinas);
	}
	
	/**
	 * Busca Armazenamento no arquivo, trata os dados e monta a lista das Disciplinas.
	 */
	private void buscarArmazenamento(){
		try{
			this.listaDisciplinas = new ArrayList<Disciplina>();
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    Disciplina disciplina;
		    String dados[];
		    List<Historico> listaHistoricos;
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	List<Turma> listaTurmaAux = buscarTurmas(Integer.parseInt(dados[0]));
		    	listaHistoricos = buscarHistorico(Integer.parseInt(dados[0]));
		    	disciplina = new Disciplina(Integer.parseInt(dados[0]),dados[1],dados[2],Integer.parseInt(dados[3]),listaTurmaAux,listaHistoricos);
		    	this.listaDisciplinas.add(disciplina);
		    	linha = lerArq.readLine();						//Lê as linhas.
		    	this.proximoId=Integer.parseInt(dados[0]);
		    }
		    this.proximoId++;		    
		    arq.close();										//Fechando o arquivo
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Busca no armazenamento usando o id de uma disciplina. É usado para quando não se quer carregar os dados para a lista.
	 * @param idDisciplina
	 * @return Disciplina
	 */
	public Disciplina buscarArmazenamentoProcurarPorId(int idDisciplina){
		try{
			FileReader arq = new FileReader(nomeArquivo);		//Cria objeto arquivo
		    BufferedReader lerArq = new BufferedReader(arq);	//Cria objeto de leitura
		    String linha=lerArq.readLine();
		    String dados[];
		    Disciplina disciplina;
		    
		    while (linha != null) {
		    	dados = linha.split("\t");
		    	if (Integer.parseInt(dados[0])==idDisciplina){
		    		disciplina = new Disciplina(Integer.parseInt(dados[0]),dados[1],dados[2],Integer.parseInt(dados[3]));
		    		return(disciplina);
		    	}
		    	linha = lerArq.readLine();						//Lê as linhas.
		    }
		    
		    arq.close();										//Fechando o arquivo
		}catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
		return(null);
	}
	
	/**
	 * Método usado para Salvar a lista do arquivo. O arquivo é sobrescrito nesse método.
	 */
	private void salvarArmazenamento(){
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(nomeArquivo));
			Iterator<Disciplina> i = listaDisciplinas.iterator();
			
			Disciplina disciplina;
			while(i.hasNext()){
				disciplina = (Disciplina) i.next();
				out.write(disciplina.toString());
			}
			
			out.close();
		} catch (IOException e) {
			System.err.printf("Erro ao manipular o arquivo: %s.\n",e.getMessage());
		}
	}
	
	/**
	 * Método de adicionar a Disciplina na lista. 
	 * É verificado se ele o código dele já existe, pois se existir não pode ser adicionado.
	 * Após inserir, o método "salvarArmazenamento()" é chamado
	 * @return true se foi possível inserir ou falso se ele foi encontrado na lista.
	 */
	public boolean adicionarDisciplina(Disciplina disciplina){
		Iterator<Disciplina> i = listaDisciplinas.iterator();
		Disciplina disciplinaComparacao;
		while(i.hasNext()){
			disciplinaComparacao = (Disciplina) i.next();
			if (disciplinaComparacao.getIdDisciplina() == disciplina.getIdDisciplina()){
				return(false);
			}
		}
		this.listaDisciplinas.add(disciplina);
		this.proximoId++;
		this.salvarArmazenamento();
		return(true);
	}
	
	/**
	 * Método para remover disciplina da lista. 
	 * Após remover o método "salvarArmazenamento" é chamado
	 * @return true se o aluno foi encontrado na lista para ser removido ou false se ele não foi encontrado.
	 */
	public boolean removerDisciplina(Disciplina disciplina){
		Iterator<Disciplina> i = listaDisciplinas.iterator();
		Disciplina disciplinaComparacao;
		boolean resultado;
		while(i.hasNext()){
			disciplinaComparacao = (Disciplina) i.next();
			if (disciplinaComparacao.getIdDisciplina() == disciplina.getIdDisciplina()){
				resultado = this.listaDisciplinas.remove(disciplinaComparacao);
				this.salvarArmazenamento();
				return(resultado);
			}
		}
		return(false);
	}
	
	/**
	 * Pesquisa de Disciplinas passando o nome
	 * @param nome
	 * @return Lista de Disciplinas cujos nomes são o que foi passado por parâmetro. A lista pode estar vazia se não houver ninguém com o nome.
	 */
	public List<Disciplina> procurarPorNome(String nome){
		List<Disciplina> listaDisciplinaNome = new ArrayList<Disciplina>();
		
		Iterator<Disciplina> i = listaDisciplinas.iterator();
		Disciplina disciplina;
		while(i.hasNext()){
			disciplina = (Disciplina) i.next();
			if (disciplina.getNome().equals(nome)){
				listaDisciplinaNome.add(disciplina);
			}
		}
		return(listaDisciplinaNome);
	}

	/**
	 * Pesquisa de Disciplinas passando o id da Disciplina
	 * @param idDisciplina
	 * @return Disciplina cujo id é igual ao id passado, ou null se nada for encontrado
	 */
	public Disciplina procurarPorId(int idDisciplina){
		Iterator<Disciplina> i = this.listaDisciplinas.iterator();
		Disciplina disciplina;
		while(i.hasNext()){
			disciplina = (Disciplina) i.next();
			if (disciplina.getIdDisciplina()==idDisciplina){
				return(disciplina);
			}
		}
		return(null);
	}
	
	/**
	 * Método para buscar os históricos que está relacionado com disciplina
	 * @param idDisciplina
	 * @return Lista de Históricos
	 */
	private List<Historico> buscarHistorico(int idDisciplina){
		HistoricoDaoImplArquivo HistoricoDao = new HistoricoDaoImplArquivo();
		return(HistoricoDao.buscarArmazenamentoProcurarPorDisciplina(idDisciplina));
	}
	
	/**
	 * Método para buscar as turmas que estão relacionadas com a Disciplina
	 * @param idDisciplina
	 * @return Lista de Turmas
	 */
	private List<Turma> buscarTurmas(int idDisciplina){
		TurmaDaoImplArquivo turmaDaoImplArquivo = new TurmaDaoImplArquivo(idDisciplina);
		List<Turma> listaTurmasDisciplina = turmaDaoImplArquivo.buscarArmazenamentoProcurarPorDisciplina(idDisciplina);
		return(listaTurmasDisciplina);
	}
				
}
